home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume8 / explode < prev    next >
Encoding:
Text File  |  1989-09-23  |  15.2 KB  |  637 lines

  1. Newsgroups: comp.sources.misc
  2. organization: York U. Computing Services
  3. subject: v08i044: explode -- a LaTeX to source-file extracter
  4. from: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5. Reply-To: davecb@nexus.yorku.ca (David Collier-Brown)
  6.  
  7. Posting-number: Volume 8, Issue 44
  8. Submitted-by: davecb@nexus.yorku.ca (David Collier-Brown)
  9. Archive-name: explode
  10.  
  11.    Well, this is a little program to pull chunks of
  12. source code out of LaTeX files and put them into one or
  13. more output files.
  14.    As the man page says, I did this as a simple tool to
  15. allow better documentation of quite simple programs, ones
  16. that could be explained easily in a fairly sequential
  17. discussion.  Since it hasn't broken on the few machines
  18. I've used it on, I'm contributing it to the net.  I believe
  19. it portable and reliable, but it's whole life has been in
  20. the Berzerkly universe...
  21.  
  22. --dave
  23.  
  24. #! /bin/sh
  25. # This is a shell archive.  Remove anything before this line, then unpack
  26. # it by saving it into a file and typing "sh file".  To overwrite existing
  27. # files, type "sh file -c".  You can also feed this as standard input via
  28. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  29. # will see the following message at the end:
  30. #        "End of shell archive."
  31. # Contents:  Makefile RCS README bar.tex explode.1 explode.c foo.tex
  32. #   unexplode
  33. # Wrapped by davecb@yunexus on Mon Sep 18 21:50:59 1989
  34. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  35. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  36.   echo shar: Will not clobber existing file \"'Makefile'\"
  37. else
  38. echo shar: Extracting \"'Makefile'\" \(508 characters\)
  39. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  40. X#
  41. X# A somewhat generic makefile, for explode
  42. X#
  43. XCC=/usr/local/gnu/gcc # Try another compiler
  44. XSRCS= explode.c
  45. XOBJS= explode.o 
  46. XCFLAGS= -g
  47. XDESTDIR= /usr/local/bin
  48. XMANDIR= /usr/local/man/man1
  49. X
  50. Xexplode: ${OBJS}
  51. X     ${CC} -o explode ${CFLAGS} ${OBJS}
  52. X
  53. Xinstall:
  54. X    install -s -m 755 explode ${DESTDIR}
  55. X    install -m 755 unexplode ${DESTDIR}
  56. X    cp explode.1 ${MANDIR}/explode.1
  57. X
  58. Xdeinstall:
  59. X    rm -f ${DESTDIR}/explode ${DESTDIR}/unexplode
  60. X    rm -f ${MANDIR}/explode.1
  61. X
  62. Xclean:
  63. X    rm -f explode *.o core a.out
  64. Xlint:
  65. X    lint explode.c
  66. END_OF_FILE
  67. if test 508 -ne `wc -c <'Makefile'`; then
  68.     echo shar: \"'Makefile'\" unpacked with wrong size!
  69. fi
  70. # end of 'Makefile'
  71. fi
  72. if test ! -d 'RCS' ; then
  73.     echo shar: Creating directory \"'RCS'\"
  74.     mkdir 'RCS'
  75. fi
  76. if test -f 'README' -a "${1}" != "-c" ; then 
  77.   echo shar: Will not clobber existing file \"'README'\"
  78. else
  79. echo shar: Extracting \"'README'\" \(154 characters\)
  80. sed "s/^X//" >'README' <<'END_OF_FILE'
  81. XThis is new, incomplet and inefficent.
  82. X    1) no state in table
  83. X    2) no error checking
  84. X    3) no line-splitting when directive in mid-line
  85. X    4) underdocumented.
  86. X
  87. END_OF_FILE
  88. if test 154 -ne `wc -c <'README'`; then
  89.     echo shar: \"'README'\" unpacked with wrong size!
  90. fi
  91. # end of 'README'
  92. fi
  93. if test -f 'bar.tex' -a "${1}" != "-c" ; then 
  94.   echo shar: Will not clobber existing file \"'bar.tex'\"
  95. else
  96. echo shar: Extracting \"'bar.tex'\" \(136 characters\)
  97. sed "s/^X//" >'bar.tex' <<'END_OF_FILE'
  98. X\file{beginning}
  99. X\begin{verbatim}
  100. Xbeginning
  101. X\end{verbatim}
  102. X
  103. X\begin{verbatim}
  104. Xmiddle
  105. X\end{verbatim}
  106. X
  107. X\begin{verbatim}
  108. Xend
  109. X\end{verbatim}
  110. END_OF_FILE
  111. if test 136 -ne `wc -c <'bar.tex'`; then
  112.     echo shar: \"'bar.tex'\" unpacked with wrong size!
  113. fi
  114. # end of 'bar.tex'
  115. fi
  116. if test -f 'explode.1' -a "${1}" != "-c" ; then 
  117.   echo shar: Will not clobber existing file \"'explode.1'\"
  118. else
  119. echo shar: Extracting \"'explode.1'\" \(1981 characters\)
  120. sed "s/^X//" >'explode.1' <<'END_OF_FILE'
  121. X.TH EXPLODE 1
  122. X.SH NAME
  123. Xexplode \- file exploder (LaTeX source-code extractor)
  124. X.SH SYNOPSIS
  125. X.B explode
  126. X.I pathname[.tex]
  127. X.sp
  128. X.B unexplode
  129. X.I pathname[.tex]
  130. X
  131. X.SH DESCRIPTION
  132. X.I explode
  133. Xtakes source code intertwined with LaTeX and emits
  134. Xjust the code, to however many files as are needed.
  135. X.I unexplode
  136. Xdeletes the files created that way.
  137. X.PP
  138. XThe syntax of the LaTeX file is very simple:
  139. X.I \\file{filename}
  140. Xnames a file to which material will be written.
  141. X.I \\begin{verbatim}
  142. Xstarts the copy to the file, and
  143. X.I \\end{verbatim}
  144. Xends it.
  145. X.PP
  146. XThe verbatim sections can be interleaved with any other
  147. Xlegal LaTeX construct, and multiple verbatims which
  148. Xfollow a single \\file directive will be written to the
  149. Xsame file.
  150. X.PP
  151. XMultiple files can be in use at any one time, and
  152. Xyou can switch between them by inserting a
  153. X\\file line.  
  154. X
  155. X.SH EXAMPLE
  156. XThe following is the simplest plausible explode-file.
  157. X.nf
  158. X.nj
  159. X
  160. X\\file{foo.h}
  161. X ...
  162. X\\begin{verbatim}
  163. Xtypedef void * FOO;
  164. X\\end{verbatim}
  165. X ...
  166. X\\file{foo.c}
  167. X\\begin{verbatim}
  168. X ...
  169. X.nf
  170. X.nj
  171. X
  172. X.SHISTORY
  173. XThis was written one afternoon when it became obvious that pr
  174. Xrewriting my Web subset was going to take a looooong time.
  175. XThis was written instead, to allow simple, multi-file programs
  176. Xto be generated from a single LaTeX source file.
  177. X.PP
  178. XThe program is extremely simple, has no options and probably never will
  179. Xhave.  The problem of multi-input, multi-output LaTeX ->
  180. Xprogramming-language coding is not something that's going to succumb
  181. Xto simple v7 filters.  In the meantime, here's the filter.
  182. X
  183. XNone at present.
  184. X
  185. X.SH SEE ALSO
  186. XLaTeX(1), tangle(1), weave(1), Donald Knuth's Web system.
  187. X
  188. X.SH AUTHORS
  189. X.nf
  190. XDave Collier-Brown (davecb@nexus.yorku.ca).
  191. X.fi
  192. X
  193. X.SH DIAGNOSTICS
  194. X``Too many output files'', if the system runs out of
  195. Xfile descriptors.
  196. X
  197. X.SH BUGS
  198. XThe limit on output files.  An earlier version
  199. Xre-used file descriptors...
  200. X.PP
  201. XThe directives need to be on a line by themselves, as
  202. Xthe whole line gets discarded after the directive
  203. Xis interpreted.
  204. END_OF_FILE
  205. if test 1981 -ne `wc -c <'explode.1'`; then
  206.     echo shar: \"'explode.1'\" unpacked with wrong size!
  207. fi
  208. # end of 'explode.1'
  209. fi
  210. if test -f 'explode.c' -a "${1}" != "-c" ; then 
  211.   echo shar: Will not clobber existing file \"'explode.c'\"
  212. else
  213. echo shar: Extracting \"'explode.c'\" \(7384 characters\)
  214. sed "s/^X//" >'explode.c' <<'END_OF_FILE'
  215. X/*
  216. X * explode -- an extact function for a latex-flavored tangle.
  217. X */
  218. X#include <stdio.h>
  219. X#include <strings.h>
  220. X
  221. X#define MAXLINE    256
  222. X#define OK    0
  223. Xchar    *ProgName = NULL;
  224. Xtypedef enum {NO=0,FILENAME,BEGIN_VERBATIM,END_VERBATIM} KEY;
  225. X
  226. X void
  227. Xmain(argc,argv) int argc; char *argv[]; {
  228. X    int    rc = 0, /* Return code from explode. */
  229. X            i;
  230. X    FILE    *fp, *lopen();
  231. X
  232. X    ProgName = argv[0];
  233. X    if (argc < 2 && isatty(0)) {
  234. X        (void) fprintf(stderr,"Usage: %s file[.tex]\n",
  235. X               ProgName);
  236. X        exit(1);
  237. X    }
  238. X    if (!isatty(0)) {
  239. X        rc = explode(stdin);
  240. X    }
  241. X    else {
  242. X        for (i=1; i < argc; i++) {
  243. X                /* printf("argv[%d] = '%s'\n",i,argv[i]); */
  244. X            if ((fp= lopen(argv[i],"r",".tex")) == NULL) {
  245. X                (void) fprintf(stderr,
  246. X                    "%s: %s \"%s\", ignored.\n",
  247. X                    ProgName, "can't open input file",
  248. X                    argv[i]);
  249. X                continue;
  250. X            }
  251. X            else {
  252. X                rc = explode(fp);
  253. X                (void) fclose(fp);
  254. X            }
  255. X        }
  256. X    }
  257. X    exit(rc);
  258. X}
  259. X
  260. X/*
  261. X * explode -- the main function, which supervises parsing
  262. X *      and output-file bookkeeping.
  263. X */
  264. X int
  265. Xexplode(fp) FILE *fp; {
  266. X    char    line[MAXLINE],      /* A place to put the line. */
  267. X            operand[MAXLINE];   /* The keyword's parameter. */
  268. X    FILE    *outFp,             /* Current output file. */
  269. X            *tFp,               /* Temporary fp. */
  270. X             *initialFile(),     /* Initial output file (/dev/null) */
  271. X            *beginFile(),       /* Start writing to taht file. */
  272. X            *endFile();         /* Stop writing to it. */
  273. X    int    initiateFile();     /* Associate a name with an fp. */
  274. X
  275. X    KEY    hasKeyWord();
  276. X
  277. X    if ((outFp= initialFile()) == NULL) {
  278. X              /* Assumed infallible. */
  279. X              (void) fprintf(stderr,"%s: unable to open \"%s\", %s.\n",
  280. X            ProgName,"/dev/null","aborting");
  281. X          exit(3);
  282. X    }
  283. X    while (fgets(line,sizeof(line),fp) != NULL) {
  284. X        switch (hasKeyWord(line,operand)) {
  285. X        case NO: /* Just write the line. */
  286. X               /* printf("body line: %s",line); */
  287. X               (void) fputs(line,outFp);
  288. X               break;
  289. X        case FILENAME: /* Collect a new filename to use. */
  290. X               /* printf("file line: %s, %s",operand,line); */
  291. X               if ( !initiateFile(operand)) {
  292. X                       (void) fprintf(stderr, 
  293. X                           "%s: can't open output file \"%s\", %s.\n",
  294. X                       ProgName, operand, "aborting");
  295. X                   exit(3);
  296. X               }
  297. X               break;
  298. X        case BEGIN_VERBATIM: /* Start writing to named file. */
  299. X               /* printf("begin line: %s, %s",operand,line); */
  300. X               if ((tFp= beginFile()) != NULL) {
  301. X                   outFp = tFp;
  302. X               }
  303. X               else {
  304. X                   /* It's "\begin{verbatim}" with no current file. */
  305. X                   (void) fputs(line,outFp);
  306. X               } 
  307. X               break;
  308. X        case END_VERBATIM: /* Stop writing to that file. */
  309. X               /* printf("end line %s, %s",operand,line); */
  310. X               if ((tFp= endFile()) != NULL) {
  311. X                   outFp = tFp;
  312. X               }
  313. X               else {
  314. X                   /* It's "\end{verbatim} with no current file". */
  315. X                   (void) fputs(line,outFp);
  316. X               } 
  317. X               break;
  318. X        }
  319. X     }
  320. X    return OK;
  321. X}
  322. X
  323. X/*
  324. X * lopen -- local open, sees if there's a file with an optional suffix.
  325. X */
  326. X FILE *
  327. Xlopen(name,mode,ext) char *name, *mode, *ext; {
  328. X    FILE    *fp, *fopen();
  329. X    char    buffer[MAXLINE],
  330. X            *strcat(), *strcpy();
  331. X
  332. X    if ((fp= fopen(name,mode)) != NULL) {
  333. X        return fp;
  334. X    }
  335. X    (void) strcat(strcpy(buffer,name),ext);
  336. X    fp = fopen(buffer,mode);
  337. X    return fp;
  338. X}
  339. X
  340. X/*
  341. X * hasKeyWord -- see if the keyword appears in the line,
  342. X *      return either NO, FILENAME, BEGIN_VERBATIM or END_VERBATIM and
  343. X *      a pointer to a null-terminated string containing
  344. X *      the parameter.  Also produces error messages if
  345. X *      the keyword-phrase is misparsed.
  346. X */
  347. X#define strchr(s,c) index(s,c)
  348. X#define streq(s1,s2) (strncmp(s1,s2,strlen(s2))==0)
  349. X KEY
  350. XhasKeyWord(line,operand) char *line; char *operand; {
  351. X        register char *p; /* Pointer to current position in string. */
  352. X        KEY      rc;      /* Result. */
  353. X    char     *skipTo();
  354. X    void     terminate(), unTerminate();
  355. X
  356. X        if ((p= strchr(line,'\\')) == NULL) {
  357. X            return NO;
  358. X    }
  359. X    else if (streq(p,"\\file{")) {
  360. X           rc = FILENAME;
  361. X    }
  362. X    else if (streq(line,"\\begin{verbatim}")) {
  363. X            rc = BEGIN_VERBATIM;
  364. X    }
  365. X    else if (streq(line,"\\end{verbatim}")) {
  366. X            rc = END_VERBATIM;
  367. X    }
  368. X    else {
  369. X            return NO;
  370. X    }
  371. X    /* It found one! Stuff "operand" with the parameter value. */
  372. X        p = skipTo(p,'{') + 1;
  373. X    terminate(p,'}');
  374. X    (void) strcpy(operand,p);
  375. X    unTerminate(p,'}');
  376. X    return rc;
  377. X}
  378. X
  379. X/*
  380. X** string utilities 
  381. X*/
  382. X char *
  383. XskipTo(p,c) register char *p; char c; {
  384. X        while (*p && *p != c)
  385. X            p++;
  386. X    return p;
  387. X      }
  388. X
  389. X void
  390. Xterminate(from,at) char *from, at; {
  391. X        while (*from && *from != at)
  392. X            from++;
  393. X    if (!*from)
  394. X            return;
  395. X    *from = '\0';
  396. X    return;
  397. X}
  398. X
  399. X void
  400. XunTerminate(from,with) char *from, with; {
  401. X        while (*from)
  402. X            from++;
  403. X    *from = with;
  404. X    return;
  405. X}
  406. X
  407. X/*
  408. X * strsave -- allocate enopugh space for a string & its terminating null.
  409. X */
  410. X char *
  411. Xstrsave(s) char *s; {
  412. X        char    *p, *malloc(), *strcpy();
  413. X
  414. X    if ((p= malloc((unsigned)strlen(s)+1)) != NULL) {
  415. X            return strcpy(p,s);
  416. X    }
  417. X    else {
  418. X            return NULL;
  419. X    }
  420. X}
  421. X
  422. X/*
  423. X** File -- output-file managment package.
  424. X**      Depends on table package.
  425. X*/
  426. X#define CURRENT "The current file"
  427. Xtypedef struct {
  428. X        char *name;
  429. X    FILE *fp;
  430. X} TABLE;
  431. X
  432. X
  433. X/*
  434. X * initialFile -- create the initial output file (/dev/null).
  435. X */
  436. X FILE *
  437. XinitialFile() {
  438. X        FILE    *fp, *fopen();
  439. X    TABLE   *addToTable();
  440. X
  441. X    if ((fp= fopen("/dev/null","w")) != NULL 
  442. X       && addToTable("/dev/null",fp) != NULL) {
  443. X            return fp;
  444. X    }
  445. X    else {
  446. X            return (FILE *) NULL;
  447. X    }
  448. X}
  449. X
  450. X/*
  451. X * initiateFile -- get a file pointer for the named file & save it.
  452. X */
  453. X int
  454. XinitiateFile(name) char *name; {
  455. X    TABLE   *getFromTable(), *addToTable();
  456. X    FILE    *fp, *fopen();
  457. X
  458. X           if (getFromTable(name) != NULL) {
  459. X            return 1;
  460. X    }
  461. X    else if ((fp= fopen(name,"w")) == NULL) {
  462. X            return 0;
  463. X    }
  464. X    else {
  465. X            return addToTable(name,fp)? 1: 0;
  466. X    }
  467. X}
  468. X
  469. X/*
  470. X * beginFile --  start writing to that file.
  471. X */
  472. X FILE *
  473. XbeginFile() {
  474. X        TABLE   *t, *getFromTable();
  475. X
  476. X        if ((t= getFromTable(CURRENT)) != NULL) {
  477. X            return t->fp;
  478. X    }
  479. X    else {
  480. X            return NULL;
  481. X        }
  482. X}
  483. X
  484. X/*
  485. X * endFile -- stop writing to it.
  486. X */
  487. X FILE *
  488. XendFile() {    
  489. X        TABLE   *getFromTable();
  490. X
  491. X        if (getFromTable(CURRENT) != NULL) {
  492. X            /* Return the replacement. */
  493. X            return getFromTable("/dev/null")->fp;
  494. X    }
  495. X    else {
  496. X            /* Otherwise don't stop using it. */
  497. X            return (FILE *) NULL;
  498. X    }
  499. X}
  500. X
  501. X
  502. X/*
  503. X * 
  504. X */
  505. X#define NFILES 30
  506. XTABLE   Table[NFILES];
  507. Xstatic int CurrentFile = -1;
  508. X
  509. X TABLE *
  510. XaddToTable(name,fp) char *name; FILE *fp; {
  511. X        static int lastLookedAt = 0;
  512. X    int     i;
  513. X    char    *strsave();
  514. X    TABLE   *t, *getFromTable();
  515. X
  516. X        if ((t= getFromTable(name)) != NULL) {
  517. X            return (TABLE *) t;
  518. X    }
  519. X    else {
  520. X            for (i=lastLookedAt; i < NFILES; i++) {
  521. X                if (Table[i].name == NULL) {
  522. X                    Table[i].name = strsave(name);
  523. X                    Table[i].fp = fp;
  524. X                CurrentFile = i;
  525. X                return &Table[i];
  526. X            }
  527. X        }
  528. X        return (TABLE *) NULL;
  529. X    }
  530. X}
  531. X
  532. X TABLE *
  533. XgetFromTable(name) char *name; {
  534. X        int     i;
  535. X
  536. X    if (streq(name,CURRENT)) {
  537. X        return (CurrentFile == -1)?  (TABLE *) NULL: &Table[CurrentFile];
  538. X    }
  539. X        for (i=0; i < NFILES && Table[i].name != NULL; i++) {
  540. X            if (streq(Table[i].name,name) != NULL) {
  541. X                return &Table[i];
  542. X        }
  543. X    }
  544. X        return (TABLE *) NULL;
  545. X}
  546. END_OF_FILE
  547. if test 7384 -ne `wc -c <'explode.c'`; then
  548.     echo shar: \"'explode.c'\" unpacked with wrong size!
  549. fi
  550. # end of 'explode.c'
  551. fi
  552. if test -f 'foo.tex' -a "${1}" != "-c" ; then 
  553.   echo shar: Will not clobber existing file \"'foo.tex'\"
  554. else
  555. echo shar: Extracting \"'foo.tex'\" \(339 characters\)
  556. sed "s/^X//" >'foo.tex' <<'END_OF_FILE'
  557. Xmake explode blow up (run out of file pointers)
  558. X\file{1}
  559. X\file{2}
  560. X\file{3}
  561. X\file{4}
  562. X\file{5}
  563. X\file{6}
  564. X\file{7}
  565. X\file{8}
  566. X\file{9}
  567. X\file{10}
  568. X\file{11}
  569. X\file{12}
  570. X\file{13}
  571. X\file{14}
  572. X\file{15}
  573. X\file{16}
  574. X\file{17}
  575. X\file{18}
  576. X\file{19}
  577. X\file{20}
  578. X\file{21}
  579. X\file{22}
  580. X\file{23}
  581. X\file{24}
  582. X\file{25}
  583. X\file{26}
  584. X\file{27}
  585. X\file{28}
  586. X\file{29}
  587. X\file{30}
  588. END_OF_FILE
  589. if test 339 -ne `wc -c <'foo.tex'`; then
  590.     echo shar: \"'foo.tex'\" unpacked with wrong size!
  591. fi
  592. # end of 'foo.tex'
  593. fi
  594. if test -f 'unexplode' -a "${1}" != "-c" ; then 
  595.   echo shar: Will not clobber existing file \"'unexplode'\"
  596. else
  597. echo shar: Extracting \"'unexplode'\" \(341 characters\)
  598. sed "s/^X//" >'unexplode' <<'END_OF_FILE'
  599. X#!/bin/sh
  600. X#
  601. X# unexplode -- delete the files cerated by explode.
  602. X#
  603. Xif [ $# -lt 1 ] ; then
  604. X    echo "unexplode -- delete files created by explode."
  605. X    echo "Usage: unexplode file"
  606. X    exit 1
  607. Xfi
  608. Xfor i in $*; do
  609. X    if [ -f $i ] ; then
  610. X        :
  611. X    else 
  612. X        if [ -f $i.tex ] ; then
  613. X            i=$i.tex
  614. X        fi
  615. X    fi
  616. X    rm -f `grep '\\file{' $i | sed '
  617. X        s/.file{//
  618. X        s/}//'`
  619. Xdone
  620. END_OF_FILE
  621. if test 341 -ne `wc -c <'unexplode'`; then
  622.     echo shar: \"'unexplode'\" unpacked with wrong size!
  623. fi
  624. chmod +x 'unexplode'
  625. # end of 'unexplode'
  626. fi
  627. echo shar: End of shell archive.
  628. exit 0
  629.  
  630.  
  631. -- 
  632. David Collier-Brown,  | davecb@yunexus, ...!yunexus!davecb or
  633. 72 Abitibi Ave.,      | {toronto area...}lethe!dave 
  634. Willowdale, Ontario,  | Joyce C-B:
  635. CANADA. 416-223-8968  |    He's so smart he's dumb.
  636.  
  637.